package com.wangge.concurrentTest.priorityBlockingQueue;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;

class PrioritizedTask implements Runnable, Comparable<PrioritizedTask> {
  private Random rand = new Random(47);
  private static int counter = 0;
  private final int id = counter++;
  private final int priority;
  protected static List<PrioritizedTask> sequence = new ArrayList<PrioritizedTask>();

  public PrioritizedTask(int priority) {
    super();
    this.priority = priority;
    sequence.add(this);
  }

  @Override
  public int compareTo(PrioritizedTask arg0) {
    return arg0.priority > this.priority ? 1 : arg0.priority < this.priority ? -1 : 0;
  }

  @Override
  public void run() {

    try {

      TimeUnit.MILLISECONDS.sleep(rand.nextInt(250));
    } catch (InterruptedException e) {
    }
    System.out.println(this);
  }

  public String toString() {
    return String.format("[%1$-3d]", priority) + " Task" + id;
  }

  public String summary() {
    return "(" + id + ":" + priority + ")";
  }

  public static class EndSentinel extends PrioritizedTask {
    private ExecutorService exec;

    public EndSentinel(ExecutorService exec) {
      super(-1);
      this.exec = exec;
    }

    public void run() {
      int count = 0;
      for (PrioritizedTask pt : sequence) {
        System.out.print(pt.summary());
        if (++count % 5 == 0) {
          System.out.println();
        }
      }
      System.out.println();
      System.out.print(this + " Calling shutdownNow()");
    }
  }
}

class PrioritizedTaskProducer implements Runnable {

  Random rand = new Random(47);
  private Queue<Runnable> queue;
  private ExecutorService exec;

  public PrioritizedTaskProducer(Queue<Runnable> queue, ExecutorService exec) {
    this.queue = queue;
    this.exec = exec;
  }

  @Override
  public void run() {
    // 通过无序的随机数将权限分给任务
    for (int i = 0; i < 20; i++) {
      queue.add(new PrioritizedTask(rand.nextInt(10)));
      Thread.yield();
    }
    try {
      // 加入权限最高的任务
      for (int i = 0; i < 10; i++) {
        TimeUnit.MILLISECONDS.sleep(250);
        queue.add(new PrioritizedTask(10));
      }
      // 加入任务,从最低权限开始
      for (int i = 0; i < 10; i++)
        queue.add(new PrioritizedTask(i));

      // 添加一个任务来中断所有的任务
      queue.add(new PrioritizedTask.EndSentinel(exec));
    } catch (InterruptedException e) {

    }
    System.out.println("finished prioritizedTaskProducer");
  }

}

class PrioritizedTaskConsumer implements Runnable {
  private PriorityBlockingQueue<Runnable> q;

  public PrioritizedTaskConsumer(PriorityBlockingQueue<Runnable> q) {
    this.q = q;
  }

  @Override
  public void run() {
    try {
      while (!Thread.interrupted()) {
        q.take().run();
      }
    } catch (InterruptedException e) {

    }
    System.out.println("finished PrioritizedTaskConsumer");
  }

}

public class PrioritizedBlockingQueueDemo {
  public static void main(String[] args) {
    ExecutorService exec = Executors.newCachedThreadPool();
    PriorityBlockingQueue<Runnable> queue = new PriorityBlockingQueue<Runnable>();
    exec.execute(new PrioritizedTaskProducer(queue, exec));
    exec.execute(new PrioritizedTaskConsumer(queue));
  }
}
